#include "Point.h"

const Point Point::ORIGIN(0.0, 0.0, 0.0);

Point::Point(const double X, const double Y, const double Z) : x(X), y(Y), z(Z) {
}

Point::Point(const Point &cpy) : x(cpy.x), y(cpy.y), z(cpy.z) {
}

void Point::set(const Point &cpy) {
	this->x = cpy.x;
	this->y = cpy.y;
	this->z = cpy.z;
}

void Point::set(const double &X, const double &Y, const double &Z) {
	this->x = X;
	this->y = Y;
	this->z = Z;
}

Point& Point::rotateAroundPivotOnX(const double &radAngle, const Point &pivot) {
	Vector vec = this->subtract(pivot).rotateOnX(radAngle);
	this->set(pivot);
	return this->add(vec);
}

Point& Point::rotateAroundPivotOnY(const double &radAngle, const Point &pivot) {
	Vector vec = this->subtract(pivot).rotateOnY(radAngle);
	this->set(pivot);
	return this->add(vec);
}

Point& Point::rotateAroundPivotOnZ(const double &radAngle, const Point &pivot) {
	Vector vec = this->subtract(pivot).rotateOnZ(radAngle);
	this->set(pivot);
	return this->add(vec);
}

double Point::distanceTo(const Point &target) const {
	return sqrt(this->squareDistanceTo(target));
}

double Point::distanceToOrigin() const {
	return sqrt(this->squareDistanceToOrigin());
}

double Point::squareDistanceTo(const Point &target) const {
	const double x = this->x * target.x;
	const double y = this->y * target.y;
	const double z = this->z * target.z;
	return (x * x) + (y * y) + (z * z);
}

double Point::squareDistanceToOrigin() const {
	return (this->x * this->x) + (this->y * this->y) + (this->z * this->z);
}

Point& Point::add(const Vector &op2) {
	this->x += op2.x;
	this->y += op2.y;
	this->z += op2.z;
	return *this;
}

Point& Point::add(const double &x, const double &y, const double &z) {
	this->x += x;
	this->y += y;
	this->z += z;
	return *this;
}

Point& Point::subtract(const Vector &op2) {
	this->x -= op2.x;
	this->y -= op2.y;
	this->z -= op2.z;
	return *this;
}

Point& Point::subtract(const double &x, const double &y, const double &z) {
	this->x -= x;
	this->y -= y;
	this->z -= z;
	return *this;
}

Vector Point::subtract(const Point &op2) const {
	return Vector(this->x - op2.x, this->y - op2.y, this->z - op2.z);
}

Point& Point::interpolate(const Point &op2, const double &alpha) {
	this->x = ((1.0 - alpha) * this->x) + (alpha * op2.x);
	this->y = ((1.0 - alpha) * this->y) + (alpha * op2.y);
	this->z = ((1.0 - alpha) * this->z) + (alpha * op2.z);
	return *this;
}

bool Point::isOrigin() const {
	if (this->x == 0.0) {
		if (this->y == 0.0) {
			return this->z == 0.0;
		}
	}
	return false;
}

bool Point::isClosestToOrigin(const Point &r) const {
	return this->squareDistanceToOrigin() < r.squareDistanceToOrigin();
}

bool Point::isFarthestFromOrigin(const Point &r) const {
	return this->squareDistanceToOrigin() > r.squareDistanceToOrigin();
}

bool Point::isClosestToPoint(const Point &point, const Point &r) const {
	return this->squareDistanceTo(point) < r.squareDistanceTo(point);
}

bool Point::isFarthestFromPoint(const Point &point, const Point &r) const {
	return this->squareDistanceTo(point) > r.squareDistanceTo(point);
}
